#ifndef _YHTML_H
#define _YHTML_H
#include <tool/ydefine.h>
#include <tool/ystr.h>

/** Use by <code>getTagCotent(..)</code>  function pointer
for finding HTML tags within char array. 
<br/><code>htmFirst</code> - find the first match, forward search.
<br/><code>htmLast</code> - find the last match, reverse search.
<br/><code>htmHug</code> - find the starting tag using forward search 
  and ending tag using reverse search.
*/
typedef enum htmlTagMatch {htmFirst, htmLast, htmHug} htmlTagMatch;

/** Function pointers struct, use externally */
typedef struct htmlFn *htmlFn;
/** Data struct, use internally */
typedef struct htmlFnData *htmlFnData;

/** struct of HTML function pointers */
struct htmlFn {
  /*--- data ---*/
  htmlFnData d;
  /*--- function pointers ---*/
  /** Set <code>htmlFn</code>'s <code>strFn</code>.
  If <code>strFn</code> is already created, 
  this action will be ignored and <code>false</code> will be returned.
  <code>htmlFn</code> will NOT free the memory of 
  <code>strFn</code> that is created externally, 
  you MUST free this yourself.
  @param fn the <code>htmlFn</code> to use.
  @param strFn pass in the <code>strFn</code> to use.
  @return <code>true</code> if successfully otherwise <code>false</code>.
  */
  boolean (*setStrFn)(htmlFn fn, strFn strFn);
  /** Free a htmlFn, free up the memory.
  @param fnP pass in the address of <code>htmlFn</code> to be free.
  @return <code>true</code> if successfully otherwise <code>false</code>.
  */
  boolean (*freeFn)(htmlFn *fnP);
  /* specific operation */
  /** Get all the content within this HTML tag, 
  content is given with pointers to its' start and end position 
  inclusive. Note function can NOT return as c string 
  since NULL characters is acceptable within content.
  Find this tag using various <code>htmlTagMatch</code> method 
  i.e. <code>htmFirst, htmLast or htmHug</code>.
  Default method is <code>htmFirst</code>.
  Those tags located within HTML comment will be ignored.
  e.g. &lt;!-- &lt;title&gt;My Page ignored&lt;/title&gt; --&gt;
  @param fn the <code>htmlFn</code> to use.
  @param ptr the pointer to the character array that is going to be search.
  @param readLen the length of the array to be read.
  @param tagWord the tag's word to be searched, 
    e.g. to find & obtain HTML &lt;title&gt;My Page&lt;/title&gt; 
    tags content, pass <code>tagWord</code> in as "title".
  @param contentStart pointer to pointer of the starting character 
    of the content (inclusive), or <code>NULL</code> if failure.
  @param contentEnd pointer to pointer of the ending character 
    of the content (inclusive), or <code>NULL</code> if failure.
  @param matchMethod indicate to use which <code>htmlTagMatch</code> method
    i.e. <code>htmFirst, htmLast or htmHug</code>.
    Default method is <code>htmFirst</code>.
  @return <code>true</code> if successfully otherwise <code>false</code>.
  */
  boolean (*getTagCotent)(htmlFn fn,
      char *ptr, const unsigned int readLen, const char *tagWord, 
      char **contentStart, char **contentEnd, htmlTagMatch matchMethod);
  /** Is tag a HTML comment tag inside this character array? (XML or HTML)
  Provide a pointer to a valid tag's first and last char (inclusive).
  Those tags located within HTML comment will NOT be ignored!
  e.g. &lt;!-- &lt;title&gt;My Page ignored&lt;/title&gt; --&gt;
  @param fn the <code>htmlFn</code> to use.
  @param ptr the pointer to the character array 
    that is going to be search.
  @param readLen the length of the array to be read.
  @param charPos pointer to anywhere within the tag that is to be tested, 
    including tag's start & end chars.
  @param tagStartChar pointer to pointer of the start char of the found tag 
    (inclusive), otherwise <code>NULL</code>.
  @param tagEndChar pointer to pointer of the end char of the found tag 
    (inclusive), otherwise <code>NULL</code>.
  @return <code>true</code> if tag is a HTML comment tag 
    otherwise <code>false</code>.
  */
  boolean (*isCommentTag)(htmlFn fn,
      char *ptr, const unsigned long readLen, 
      char *charPos, char **tagStartChar, char **tagEndChar);
  /** Is tag a start or end tag inside this character array? (XML or HTML)
  Provide a pointer to a valid tag's first and last char (inclusive).
  Those tags located within HTML comment will NOT be ignored!
  e.g. &lt;!-- &lt;title&gt;My Page ignored&lt;/title&gt; --&gt;
  @param fn the <code>htmlFn</code> to use.
  @param ptr the pointer to the character array 
    that is going to be search.
  @param readLen the length of the array to be read.
  @param charPos pointer to anywhere within the tag that is to be tested, 
    including tag's start & end chars.
  @param tagStartChar pointer to pointer of the start char of the found tag 
    (inclusive), otherwise <code>NULL</code>.
  @param tagEndChar pointer to pointer of the end char of the found tag 
    (inclusive), otherwise <code>NULL</code>.
  @return <code>true</code> if successfully otherwise <code>false</code>.
  */
  boolean (*isTag)(htmlFn fn,
      const char *ptr, const unsigned long readLen, 
      const char *charPos, char **tagStartChar, char **tagEndChar);
  /** Is tag a start tag inside this character array? (XML or HTML)
  Provide a pointer to a valid tag's first and last char (inclusive).
  Those tags located within HTML comment will NOT be ignored!
  e.g. &lt;!-- &lt;title&gt;My Page ignored&lt;/title&gt; --&gt;
  A Starting tag e.g. &lt;title&gt;
  @param fn the <code>htmlFn</code> to use.
  @param ptr the pointer to the character array 
    that is going to be search.
  @param readLen the length of the array to be read.
  @param tagWord the tag's word to be searched, 
    e.g. to find HTML &lt;title&gt; OR &lt;/title&gt; 
    tag, pass <code>tagWord</code> in as "title".
  @param charPos pointer to anywhere within the tag that is to be tested, 
    including tag's start & end chars.
  @param tagStartChar pointer to pointer of the start char of the found tag 
    (inclusive), otherwise <code>NULL</code>.
  @param tagEndChar pointer to pointer of the end char of the found tag 
    (inclusive), otherwise <code>NULL</code>.
  @return <code>true</code> if successfully otherwise <code>false</code>.
  */
  boolean (*isStartTag)(htmlFn fn,
      const char *ptr, const unsigned long readLen, 
      const char *tagWord, const char *charPos, 
      char **tagStartChar, char **tagEndChar);
  /** Is tag an end tag inside this character array? (XML or HTML)
  Provide a pointer to a valid tag's first and last char (inclusive).
  Those tags located within HTML comment will NOT be ignored!
  e.g. &lt;!-- &lt;title&gt;My Page ignored&lt;/title&gt; --&gt;
  An ending tag e.g &lt;/title&gt;
  @param fn the <code>htmlFn</code> to use.
  @param ptr the pointer to the character array 
    that is going to be search.
  @param readLen the length of the array to be read.
  @param tagWord the tag's word to be searched, 
    e.g. to find HTML &lt;title&gt; OR &lt;/title&gt; 
    tag, pass <code>tagWord</code> in as "title".
  @param charPos pointer to anywhere within the tag that is to be tested, 
    including tag's start & end chars.
  @param tagStartChar pointer to pointer of the start char of the found tag 
    (inclusive), otherwise <code>NULL</code>.
  @param tagEndChar pointer to pointer of the end char of the found tag 
    (inclusive), otherwise <code>NULL</code>.
  @return <code>true</code> if successfully otherwise <code>false</code>.
  */
  boolean (*isEndTag)(htmlFn fn,
      const char *ptr, const unsigned long readLen, 
      const char *tagWord, const char *charPos, 
      char **tagStartChar, char **tagEndChar);
  /** Is tag "in action" 
  inside this character array? (XML or HTML)
  Provide a pointer to a valid tag's first and last char (inclusive).
  Those tags located within HTML comment will be ignored.
  e.g. &lt;!-- &lt;title&gt;My Page ignored&lt;/title&gt; --&gt;
  A starting tag e.g. &lt;title&gt;
  @param fn the <code>htmlFn</code> to use.
  @param ptr the pointer to the character array 
    that is going to be search.
  @param readLen the length of the array to be read.
  @param charPos pointer to anywhere within the tag that is to be tested, 
    including tag's start & end chars.
  @param tagStartChar pointer to pointer of the start char of the found tag 
    (inclusive), otherwise <code>NULL</code>.
  @param tagEndChar pointer to pointer of the end char of the found tag 
    (inclusive), otherwise <code>NULL</code>.
  @return <code>true</code> if successfully otherwise <code>false</code>.
  */
  boolean (*isTagInAction)(htmlFn fn,
      char *ptr, const unsigned long readLen, 
      char *charPos, char **tagStartChar, char **tagEndChar);
  /** Is tag a start tag "in action" 
  inside this character array? (XML or HTML)
  Provide a pointer to a valid tag's first and last char (inclusive).
  Those tags located within HTML comment will be ignored.
  e.g. &lt;!-- &lt;title&gt;My Page ignored&lt;/title&gt; --&gt;
  A starting tag e.g. &lt;title&gt;
  @param fn the <code>htmlFn</code> to use.
  @param ptr the pointer to the character array 
    that is going to be search.
  @param readLen the length of the array to be read.
  @param tagWord the tag's word to be searched, 
    e.g. to find HTML &lt;title&gt; OR &lt;/title&gt; 
    tag, pass <code>tagWord</code> in as "title".
  @param charPos pointer to anywhere within the tag that is to be tested, 
    including tag's start & end chars.
  @param tagStartChar pointer to pointer of the start char of the found tag 
    (inclusive), otherwise <code>NULL</code>.
  @param tagEndChar pointer to pointer of the end char of the found tag 
    (inclusive), otherwise <code>NULL</code>.
  @return <code>true</code> if successfully otherwise <code>false</code>.
  */
  boolean (*isStartTagInAction)(htmlFn fn,
      char *ptr, const unsigned long readLen, 
      const char *tagWord, char *charPos, 
      char **tagStartChar, char **tagEndChar);
  /** Is tag an end tag "in action" 
  inside this character array? (XML or HTML)
  Provide a pointer to a valid tag's first and last char (inclusive).
  Those tags located within HTML comment will be ignored.
  e.g. &lt;!-- &lt;title&gt;My Page ignored&lt;/title&gt; --&gt;
  An ending tag e.g &lt;/title&gt;
  @param fn the <code>htmlFn</code> to use.
  @param ptr the pointer to the character array 
    that is going to be search.
  @param readLen the length of the array to be read.
  @param tagWord the tag's word to be searched, 
    e.g. to find HTML &lt;title&gt; OR &lt;/title&gt; 
    tag, pass <code>tagWord</code> in as "title".
  @param charPos pointer to anywhere within the tag that is to be tested, 
    including tag's start & end chars.
  @param tagStartChar pointer to pointer of the start char of the found tag 
    (inclusive), otherwise <code>NULL</code>.
  @param tagEndChar pointer to pointer of the end char of the found tag 
    (inclusive), otherwise <code>NULL</code>.
  @return <code>true</code> if successfully otherwise <code>false</code>.
  */
  boolean (*isEndTagInAction)(htmlFn fn,
      char *ptr, const unsigned long readLen, 
      const char *tagWord, char *charPos, 
      char **tagStartChar, char **tagEndChar);
  /** Is this char located within a HTML comment tag?
  @param fn the <code>htmlFn</code> to use.
  @param ptr the pointer to the character array 
    that is going to be search.
  @param readLen the length of the array to be read.
  @param charPos pointer to this char that is to be tested.
  @return <code>true</code> if it lies inside a HTML comment tag 
    otherwise <code>false</code>.
  */
  boolean (*isInCommentTag)(htmlFn fn,
      char *ptr, const unsigned long readLen, char *charPos);
  /** Find the first occurance of the HTML start tag,
  return a pointer to its' first char (inclusive).
  Those tags located within HTML comment will be ignored.
  e.g. &lt;!-- &lt;title&gt;My Page ignored&lt;/title&gt; --&gt;
  @param fn the <code>htmlFn</code> to use.
  @param ptr the pointer to the character array 
    that is going to be search.
  @param readLen the length of the array to be read.
  @param tagWord the tag's word to be searched, 
    e.g. to find HTML &lt;title&gt; OR &lt;/title&gt; 
    tag, pass <code>tagWord</code> in as "title".
  @param tagEndChar pointer to pointer of the end char of the found tag 
    (inclusive), otherwise <code>NULL</code>.
  @return pointer to the first char of the tag (inclusive), otherwise
    <code>NULL</code>.
  */
  char *(*getFirstStartTag)(htmlFn fn,
      char *ptr, const unsigned long readLen, 
      const char *tagWord, char **tagEndChar);
  /** Find the first occurance of the HTML end tag,
  return a pointer to its' first char (inclusive).
  Those tags located within HTML comment will be ignored.
  e.g. &lt;!-- &lt;title&gt;My Page ignored&lt;/title&gt; --&gt;
  @param fn the <code>htmlFn</code> to use.
  @param ptr the pointer to the character array 
    that is going to be search.
  @param readLen the length of the array to be read.
  @param tagWord the tag's word to be searched, 
    e.g. to find HTML &lt;title&gt; OR &lt;/title&gt; 
    tag, pass <code>tagWord</code> in as "title".
  @param tagEndChar pointer to pointer of the end char of the found tag 
    (inclusive), otherwise <code>NULL</code>.
  @return pointer to the first char of the tag (inclusive), otherwise
    <code>NULL</code>.
  */
  char *(*getFirstEndTag)(htmlFn fn,
      char *ptr, const unsigned long readLen, 
      const char *tagWord, char **tagEndChar);
  /** Find the last occurance of the HTML start tag,
  return a pointer to its' first char (inclusive).
  Those tags located within HTML comment will be ignored.
  e.g. &lt;!-- &lt;title&gt;My Page ignored&lt;/title&gt; --&gt;
  @param fn the <code>htmlFn</code> to use.
  @param ptr the pointer to the character array 
    that is going to be search.
  @param readLen the length of the array to be read.
  @param tagWord the tag's word to be searched, 
    e.g. to find HTML &lt;title&gt; OR &lt;/title&gt; 
    tag, pass <code>tagWord</code> in as "title".
  @param tagEndChar pointer to pointer of the end char of the found tag 
    (inclusive), otherwise <code>NULL</code>.
  @return pointer to the first char of the tag (inclusive), otherwise
    <code>NULL</code>.
  */
  char *(*getLastStartTag)(htmlFn fn,
      char *ptr, const unsigned long readLen, 
      const char *tagWord, char **tagEndChar);
  /** Find the last occurance of the HTML end tag,
  return a pointer to its' first char (inclusive).
  Those tags located within HTML comment will be ignored.
  e.g. &lt;!-- &lt;title&gt;My Page ignored&lt;/title&gt; --&gt;
  @param fn the <code>htmlFn</code> to use.
  @param ptr the pointer to the character array 
    that is going to be search.
  @param readLen the length of the array to be read.
  @param tagWord the tag's word to be searched, 
    e.g. to find HTML &lt;title&gt; OR &lt;/title&gt; 
    tag, pass <code>tagWord</code> in as "title".
  @param tagEndChar pointer to pointer of the end char of the found tag 
    (inclusive), otherwise <code>NULL</code>.
  @return pointer to the first char of the tag (inclusive), otherwise
    <code>NULL</code>.
  */
  char *(*getLastEndTag)(htmlFn fn,
      char *ptr, const unsigned long readLen, 
      const char *tagWord, char **tagEndChar);
  /** Test if this is an Entity string. 
  i.e. a HTML 4.01 Entities Name or Entities Number.
  <p>NOTE: this function does NOT check an exact 
  HTML 4.01 Entities Name or Entities Number.
  If it start with '&', ends with ';' and has alphabets 
  inbetween, then this is assume to be an Entities Name.
  If it start with "&#", ends with ';' and has digits
  inbetween, then this is assume to be an Entities Number.
  </p>
  <br/>Entities Name e.g. &nbsp; is the non-breaking space.
  <br/>Entity Number e.g. &#34; is the double quote.
  @param str the string.
  @param strLen the length of the string to be check to.
  @return Return none zero or the length of the Entity string. 
    Return zero if it is NOT an Entity string.
  */
  unsigned char (*isHtmlEntityStr)(const char *str, 
      const unsigned int strLen);
  /** Number of place to skip. If this is an Entity string, 
  i.e. a HTML 4.01 Entities Name or Entities Number,
  place to skip is the Entity string length. 
  <p>If string starts with "&#" but NOT an Entity string 
  (as defined in this function), place to skip is 2.
  If string starts with '&' but NOT an Entity string 
  (as defined in this function), place to skip is 1.
  If string does NOT start with "&#" or '&', place to skip is 0.
  </p>
  <p>NOTE: this function does NOT check an exact 
  HTML 4.01 Entities Name or Entities Number.
  If it start with '&', ends with ';' and has alphabets 
  inbetween, then this is assume to be an Entities Name.
  If it start with "&#", ends with ';' and has digits
  inbetween, then this is assume to be an Entities Number.
  </p>
  <br/>Entities Name e.g. &nbsp; is the non-breaking space.
  <br/>Entity Number e.g. &#34; is the double quote.
  @param str the string.
  @param strLen the length of the string to be check to.
  @return Return none zero or the number of place to skip 
    if it is an Entity string. 
    Return zero if it is NOT an Entity string.
  */
  unsigned char (*skipHtmlEntityStr)(const char *str, 
      const unsigned int strLen);
};

/** Create a <code>htmlFn</code> that provide yhtml function pointers.
@return the struct of yhtml function pointers
  or <code>NULL</code> if failure.
*/
htmlFn yhtml_createFn(void);

#endif /* _YHTML_H */
